﻿using Authorization.Center.Jwt;
using Com.Ctrip.Framework.Apollo;
using Com.Ctrip.Framework.Apollo.Logging;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using S.Parturition.Infrastructure.Impl;
using S.Parturition.Infrastructure.Interface;
using Serilog;
using Serilog.Events;
using System.Reflection;
using System.Text;

namespace S.Parturition.Read.API.Extensions
{
    public static class IOCServer
    {

        /// <summary>
        /// 注入JWT授权
        /// </summary>
        /// <param name="builder"></param>
        public static void AddJwtServer(this WebApplicationBuilder builder)
        {
            #region 配置授权校验规则

            //
            //var secretByte = Encoding.UTF8.GetBytes(builder.Configuration["JWTTokenOptions"]);
            JWTTokenOptions tokenOptions = new JWTTokenOptions();
            builder.Configuration.Bind("JWTToken", tokenOptions);
            builder.Services
                .AddAuthorization() //启用授权
                .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) //指定授权的渠道
                 .AddJwtBearer(options =>  //这里是配置的鉴权的逻辑
                 {
                     //解开token以后，需要校验的相关信息
                     options.TokenValidationParameters = new TokenValidationParameters
                     {
                         //JWT有一些默认的属性，就是给鉴权时就可以筛选了
                         ValidateIssuer = true,//是否验证Issuer发布者
                         ValidateAudience = true,//是否验证Audience接受者
                         ValidateLifetime = true,//是否验证失效时间
                         ValidateIssuerSigningKey = true,//是否验证SecurityKey
                         ValidAudience = tokenOptions.Audience,//
                         ValidIssuer = tokenOptions.Issuer,//Issuer，这两项和前面签发jwt的设置一致
                         IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenOptions.SecurityKey)),
                         AudienceValidator = (m, n, z) =>
                         {
                             //这里可以写自己定义的验证逻辑
                             //return m != null && m.FirstOrDefault().Equals(builder.Configuration["audience"]);
                             return true;
                         },
                         LifetimeValidator = (notBefore, expires, securityToken, validationParameters) =>
                         {
                             //return notBefore <= DateTime.Now
                             //&& expires >= DateTime.Now;
                             ////&& validationParameters

                             return true;
                         }//自定义校验规则
                     };
                 });

            #endregion 配置授权校验规则
        }



        /// <summary>
        /// 注入仓储模式
        /// </summary>
        /// <param name="builder"></param>
        public static void AddRepository(this WebApplicationBuilder builder)
        {
            builder.Services.AddScoped<IParturitionRepository, ParturitionRepository>();
            builder.Services.AddScoped<ILambRegistrationRepository, LambRegistrationRepository>();
        }


        /// <summary>
        /// 注入apollo配置中心
        /// </summary>
        /// <param name="builder"></param>
        public static void AddApollo(this WebApplicationBuilder builder)
        {
            builder.Host.ConfigureAppConfiguration((hostingContext, bur) =>
            {
                LogManager.UseConsoleLogging
                (Com.Ctrip.Framework.Apollo.Logging.LogLevel.Trace); bur.AddApollo(bur.Build().GetSection
                ("Apollo")).AddDefault();
            });
        }


        /// <summary>
        /// 注入跨域配置
        /// </summary>
        /// <param name="builder"></param>
        public static void AddCors(this WebApplicationBuilder builder)
        {
            #region 跨域

            builder.Services.AddCors(x =>
            {
                x.AddPolicy("Parturition"
                    , policy =>
                    {
                        policy.SetIsOriginAllowed((host) => true)   //基础跨域配置
                        .AllowAnyHeader()                           //允许任何头部来源
                        .AllowCredentials()                           //允许任何的请求证书
                        .AllowAnyMethod()                           //允许所有请求方法
                        .WithExposedHeaders();
                    });
            });

            #endregion
        }



        /// <summary>
        /// 注入swagger配置
        /// </summary>
        /// <param name="builder"></param>
        public static void AddSwagger(this WebApplicationBuilder builder)
        {
            #region swagger 配置

            //swagger添加报文头，方便做登录和退出：
            builder.Services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "种母分娩读接口", Version = "v1" });
                //配置注释显示swagge ui当中
                var xmlfile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                var xmlpath = Path.Combine(AppContext.BaseDirectory, xmlfile);
                c.IncludeXmlComments(xmlpath, true);
                //Token绑定到configureServices
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                    Type = SecuritySchemeType.ApiKey,
                    Description = "直接在下框中输入Bearer {token}（注意两者之间是一个空格）",
                    Name = "Authorization",//jwt默认的参数名称
                    BearerFormat = "JWT",
                    Scheme = "Bearer"
                });
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference=new OpenApiReference
                            {
                                Type=ReferenceType.SecurityScheme,
                                Id="Bearer"
                            }
                        },
                        new string[] {}
                    }
                });
            });

            #endregion swagger 配置
        }

        /// <summary>
        /// Serilog日志
        /// </summary>
        /// <param name="builder"></param>
        public static void AddSerilog(this WebApplicationBuilder builder)
        {
            Log.Logger = new LoggerConfiguration()
               .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) // 排除Microsoft的日志
               .Enrich.FromLogContext() // 注册日志上下文
               .WriteTo.Logger(configure => configure // 输出到文件
                   .MinimumLevel.Debug()
                   .WriteTo.File(
                       $"logs\\log.txt", // 单个日志文件，总日志，所有日志存到这里面
                       rollingInterval: RollingInterval.Day,
                       outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u20}] {Message:lj}{NewLine}"
                   )
               )
               .CreateLogger();
            builder.Host.UseSerilog();
        }


    }
}
